﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Collections;
using System.Data.Linq;

namespace CoolCode.Data.Xml
{
    /// <summary>
    /// IQueryable of T part of LINQ to Xml
    /// </summary>
    /// <typeparam name="T">Type to operate on</typeparam>
    class XmlQueryable <T>: IOrderedQueryable<T>, IEnumerable<T>
    {

        /// <summary>
        /// init with XmlContext
        /// </summary>
        /// <param name="context"></param>
        public XmlQueryable(CoolCode.Data.Linq.IDataContext context)
        {
            Provider = new XmlQueryProvider();
            Expression = Expression.Constant(this);

            // lets provider reach back to XmlContext, 
            // where execute implementation resides
            (Provider as XmlQueryProvider).Context = context;
        }

        /// <summary>
        /// modified as internal because LINQ to Xml is Unusable 
        /// without XmlContext, but provider still needs access
        /// </summary>
        /// <param name="provider">IQueryProvider</param>
        /// <param name="expression">Expression Tree</param>
        internal XmlQueryable(
            XmlQueryProvider provider,
            Expression expression)
        {
            if (provider == null)
            {
                throw new ArgumentNullException("provider");
            }

            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }

            if (!typeof(IQueryable<T>).IsAssignableFrom(expression.Type))
            {
                throw new ArgumentOutOfRangeException("expression");
            }

            Provider = provider;
            Expression = expression;
        }

        /// <summary>
        /// IQueryProvider part of LINQ to Xml
        /// </summary>
        public IQueryProvider Provider { get; private set; }

        /// <summary>
        /// expression tree
        /// </summary>
        public Expression Expression { get; private set; }

        /// <summary>
        /// type of T in IQueryable of T
        /// </summary>
        public Type ElementType
        {
            get { return typeof(T); }
        }

        /// <summary>
        /// executes when iterating over collection
        /// </summary>
        /// <returns>query results</returns>
        public IEnumerator<T> GetEnumerator()
        {
            //return (Provider.Execute<IEnumerable<T>>(Expression)).GetEnumerator();
           return   (Provider as XmlQueryProvider).Execute<T>(Expression, true).GetEnumerator();
        }

        /// <summary>
        /// non-generic execution when collection is iterated over
        /// </summary>
        /// <returns>query results</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return (Provider.Execute<IEnumerable>(Expression)).GetEnumerator();
        }

        #region IEnumerable<T> Members

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }
}

